CREATE OR REPLACE FUNCTION pgtap_version()RETURNS NUMERIC AS 'SELECT 0.95;'LANGUAGE SQL IMMUTABLE;
CREATE OR REPLACE FUNCTION plan( integer )RETURNS TEXT AS $$DECLARE    rcount INTEGER;
BEGIN    BEGIN        EXECUTE '            CREATE TEMP SEQUENCE __tcache___id_seq;
            CREATE TEMP TABLE __tcache__ (                id    INTEGER NOT NULL DEFAULT nextval(''__tcache___id_seq''),                label TEXT    NOT NULL,                value INTEGER NOT NULL,                note  TEXT    NOT NULL DEFAULT ''''            );
            CREATE UNIQUE INDEX __tcache___key ON __tcache__(id);
            GRANT ALL ON TABLE __tcache__ TO PUBLIC;
            GRANT ALL ON TABLE __tcache___id_seq TO PUBLIC;
            CREATE TEMP SEQUENCE __tresults___numb_seq;
            GRANT ALL ON TABLE __tresults___numb_seq TO PUBLIC;
        ';
    EXCEPTION WHEN duplicate_table THEN                EXECUTE 'SELECT TRUE FROM __tcache__ WHERE label = ''plan''';
      GET DIAGNOSTICS rcount = ROW_COUNT;
        IF rcount > 0 THEN           RAISE EXCEPTION 'You tried to plan twice!';
        END IF;
    END;
        PERFORM _set('plan', $1 );
    PERFORM _set('failed', 0 );
    RETURN '1..' || $1;
END;
$$ LANGUAGE plpgsql strict;
CREATE OR REPLACE FUNCTION add_result ( bool, bool, text, text, text )RETURNS integer AS $$BEGIN    IF NOT $1 THEN PERFORM _set('failed', _get('failed') + 1);
 END IF;
 END IF;
    RETURN nextval('__tresults___numb_seq');
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION num_failed ()RETURNS INTEGER AS $$    SELECT _get('failed');
$$ LANGUAGE SQL strict;
CREATE OR REPLACE FUNCTION _finish (INTEGER, INTEGER, INTEGER)RETURNS SETOF TEXT AS $$DECLARE    curr_test ALIAS FOR $1;
    exp_tests INTEGER := $2;
    num_faild ALIAS FOR $3;
    plural    CHAR;
BEGIN    plural    := CASE exp_tests WHEN 1 THEN '' ELSE 's' END;
    IF curr_test IS NULL THEN        RAISE EXCEPTION '# No tests run!';
    END IF;
    IF exp_tests = 0 OR exp_tests IS NULL THEN                 exp_tests = curr_test;
        RETURN NEXT '1..' || exp_tests;
    END IF;
    IF curr_test <> exp_tests THEN        RETURN NEXT diag(            'Looks like you planned ' || exp_tests || ' test' ||            plural || ' but ran ' || curr_test        );
    ELSIF num_faild > 0 THEN        RETURN NEXT diag(            'Looks like you failed ' || num_faild || ' test' ||            CASE num_faild WHEN 1 THEN '' ELSE 's' END            || ' of ' || exp_tests        );
    ELSE    END IF;
    RETURN;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION is_member_of( NAME, NAME[], TEXT )RETURNS TEXT AS $$DECLARE    missing text[];
BEGIN    IF NOT _has_role($1) THEN        RETURN fail( $3 ) || E'\n' || diag (            '    Role ' || quote_ident($1) || ' does not exist'        );
    END IF;
    SELECT ARRAY(        SELECT quote_ident($2[i])          FROM generate_series(1, array_upper($2, 1)) s(i)          LEFT JOIN pg_catalog.pg_roles r ON rolname = $2[i]         WHERE r.oid IS NULL            OR NOT r.oid = ANY ( _grolist($1) )         ORDER BY s.i    ) INTO missing;
    IF missing[1] IS NULL THEN        RETURN ok( true, $3 );
    END IF;
    RETURN ok( false, $3 ) || E'\n' || diag(        '    Members missing from the ' || quote_ident($1) || E' role:\n        ' ||        array_to_string( missing, E'\n        ')    );
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION is_member_of( NAME, NAME[] )RETURNS TEXT AS $$    SELECT is_member_of( $1, $2, 'Should have members of role ' || quote_ident($1) );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME, NAME[], TEXT )RETURNS TEXT AS $$    SELECT _are( 'foreign tables', _extras('f', $1, $2), _missing('f', $1, $2), $3);
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION materialized_views_are ( NAME, NAME[], TEXT )RETURNS TEXT AS $$    SELECT _are( 'Materialized views', _extras('m', $1, $2), _missing('m', $1, $2), $3);
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION materialized_views_are ( NAME[], TEXT )RETURNS TEXT AS $$    SELECT _are( 'Materialized views', _extras('m', $1), _missing('m', $1), $2);
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION materialized_views_are ( NAME, NAME[] )RETURNS TEXT AS $$    SELECT _are(        'Materialized views', _extras('m', $1, $2), _missing('m', $1, $2),        'Schema ' || quote_ident($1) || ' should have the correct materialized views'    );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION materialized_views_are ( NAME[] )RETURNS TEXT AS $$    SELECT _are(        'Materialized views', _extras('m', $1), _missing('m', $1),        'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct materialized views'    );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, NAME, TEXT )RETURNS TEXT AS $$DECLARE    owner NAME := _get_rel_owner('m'::char, $1, $2);
BEGIN        IF owner IS NULL THEN        RETURN ok(FALSE, $4) || E'\n' || diag(            E'    Materialized view ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist'        );
    END IF;
    RETURN is(owner, $3, $4);
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, NAME )RETURNS TEXT AS $$    SELECT materialized_view_owner_is(        $1, $2, $3,        'Materialized view ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3)    );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, TEXT )RETURNS TEXT AS $$DECLARE    owner NAME := _get_rel_owner('m'::char, $1);
BEGIN        IF owner IS NULL THEN        RETURN ok(FALSE, $3) || E'\n' || diag(            E'    Materialized view ' || quote_ident($1) || ' does not exist'        );
    END IF;
    RETURN is(owner, $2, $3);
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME )RETURNS TEXT AS $$    SELECT materialized_view_owner_is(        $1, $2,        'Materialized view ' || quote_ident($1) || ' should be owned by ' || quote_ident($2)    );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION has_materialized_view ( NAME, NAME, TEXT )RETURNS TEXT AS $$    SELECT ok( _rexists( 'm', $1, $2 ), $3 );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION has_materialized_view ( NAME, TEXT )RETURNS TEXT AS $$    SELECT ok( _rexists( 'm', $1 ), $2 );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION has_materialized_view ( NAME )RETURNS TEXT AS $$    SELECT has_materialized_view( $1, 'Materialized view ' || quote_ident($1) || ' should exist' );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME, NAME, TEXT )RETURNS TEXT AS $$    SELECT ok( NOT _rexists( 'm', $1, $2 ), $3 );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME, TEXT )RETURNS TEXT AS $$    SELECT ok( NOT _rexists( 'm', $1 ), $2 );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME )RETURNS TEXT AS $$    SELECT hasnt_materialized_view( $1, 'Materialized view ' || quote_ident($1) || ' should not exist' );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME[], TEXT )RETURNS TEXT AS $$    SELECT _are( 'foreign tables', _extras('f', $1), _missing('f', $1), $2);
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME, NAME[] )RETURNS TEXT AS $$    SELECT _are(        'foreign tables', _extras('f', $1, $2), _missing('f', $1, $2),        'Schema ' || quote_ident($1) || ' should have the correct foreign tables'    );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME[] )RETURNS TEXT AS $$    SELECT _are(        'foreign tables', _extras('f', $1), _missing('f', $1),        'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct foreign tables'    );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION _fix_enum_has_labels() RETURNS  VOID LANGUAGE PLPGSQL AS $FIX$BEGIN    IF pg_version_num() < 90100 THEN RETURN;
 END IF;
 END IF;
    EXECUTE $RUN$                CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME, NAME[], TEXT )        RETURNS TEXT AS $$            SELECT is(                ARRAY(                    SELECT e.enumlabel                      FROM pg_catalog.pg_type t                      JOIN pg_catalog.pg_enum e      ON t.oid = e.enumtypid                      JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid                      WHERE t.typisdefined                       AND n.nspname = $1                       AND t.typname = $2                       AND t.typtype = 'e'                     ORDER BY e.enumsortorder                ),                $3,                $4            );
        $$ LANGUAGE sql;
                CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME[], TEXT )        RETURNS TEXT AS $$            SELECT is(                ARRAY(                    SELECT e.enumlabel                      FROM pg_catalog.pg_type t                      JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid                      WHERE t.typisdefined                       AND pg_catalog.pg_type_is_visible(t.oid)                       AND t.typname = $1                       AND t.typtype = 'e'                     ORDER BY e.enumsortorder                ),                $2,                $3            );
        $$ LANGUAGE sql;
    $RUN$;
END;
$FIX$;
SELECT _fix_enum_has_labels();
DROP FUNCTION _fix_enum_has_labels();
CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME, NAME[], TEXT )RETURNS TEXT AS $$    SELECT _func_compare($1, $2, $3, NOT _strict($1, $2, $3), $4 );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME, NAME[] )RETURNS TEXT AS $$    SELECT ok(        NOT _strict($1, $2, $3),        'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' ||        array_to_string($3, ', ') || ') should not be strict'    );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME, TEXT )RETURNS TEXT AS $$    SELECT _func_compare($1, $2, NOT _strict($1, $2), $3 );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME )RETURNS TEXT AS $$    SELECT ok(        NOT _strict($1, $2),        'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be strict'    );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME[], TEXT )RETURNS TEXT AS $$    SELECT _func_compare(NULL, $1, $2, NOT _strict($1, $2), $3 );
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME[] )RETURNS TEXT AS $$    SELECT ok(        NOT _strict($1, $2),        'Function ' || quote_ident($1) || '(' ||        array_to_string($2, ', ') || ') should not be strict'    );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION isnt_strict( NAME, TEXT )RETURNS TEXT AS $$    SELECT _func_compare(NULL, $1, NOT _strict($1), $2 );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION isnt_strict( NAME )RETURNS TEXT AS $$    SELECT ok( NOT _strict($1), 'Function ' || quote_ident($1) || '() should not be strict' );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME[] )RETURNS TEXT AS $$    SELECT col_is_unique( $1, $2, $3, 'Columns ' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should have a unique constraint' );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME )RETURNS TEXT AS $$    SELECT col_is_unique( $1, $2, ARRAY[$3], 'Column ' || quote_ident($2) || '(' || quote_ident($3) || ') should have a unique constraint' );
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION _runner( text[], text[], text[], text[], text[] )RETURNS SETOF TEXT AS $$DECLARE    startup  ALIAS FOR $1;
    shutdown ALIAS FOR $2;
    setup    ALIAS FOR $3;
    teardown ALIAS FOR $4;
    tests    ALIAS FOR $5;
    tap      TEXT;
    tfaild   INTEGER := 0;
    ffaild   INTEGER := 0;
    tnumb    INTEGER := 0;
    fnumb    INTEGER := 0;
    tok      BOOLEAN := TRUE;
    errmsg   TEXT;
BEGIN    BEGIN                PERFORM * FROM no_plan();
        FOR tap IN SELECT * FROM _runem(startup, false) LOOP RETURN NEXT tap;
 END LOOP;
 END LOOP;
    EXCEPTION                        WHEN raise_exception THEN RAISE EXCEPTION '%', SQLERRM;
    END;
        tfaild := num_failed();
    FOR i IN 1..COALESCE(array_upper(tests, 1), 0) LOOP                RETURN NEXT '    ' || diag_test_name('Subtest: ' || tests[i]);
                tok := TRUE;
        tnumb := COALESCE(_get('curr_test'), 0);
        IF tnumb > 0 THEN            EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH 1';
            PERFORM _set('curr_test', 0);
            PERFORM _set('failed', 0);
        END IF;
        BEGIN            BEGIN                                FOR tap IN SELECT * FROM _runem(setup, false) LOOP                    RETURN NEXT regexp_replace(tap, '^', '    ', 'gn');
                END LOOP;
                                FOR tap IN EXECUTE 'SELECT * FROM ' || tests[i] || '()' LOOP                    RETURN NEXT regexp_replace(tap, '^', '    ', 'gn');
                END LOOP;
                                FOR tap IN SELECT * FROM _runem(teardown, false) LOOP                    RETURN NEXT regexp_replace(tap, '^', '    ', 'gn');
                END LOOP;
                                fnumb := COALESCE(_get('curr_test'), 0);
                RETURN NEXT '    1..' || fnumb;
                                IF fnumb = 0 THEN                    RETURN NEXT '    # No tests run!';
                    tok = false;
                ELSE                                        ffaild := num_failed();
                    IF ffaild > 0 THEN                        tok := FALSE;
                        RETURN NEXT '    ' || diag(                            'Looks like you failed ' || ffaild || ' test' ||                             CASE tfaild WHEN 1 THEN '' ELSE 's' END                             || ' of ' || fnumb                        );
                    END IF;
                END IF;
            EXCEPTION WHEN raise_exception THEN                                errmsg := SQLERRM;
            END;
                        RAISE EXCEPTION '__TAP_ROLLBACK__';
        EXCEPTION WHEN raise_exception THEN            IF errmsg IS NOT NULL THEN                                tok := FALSE;
                RETURN NEXT '    ' || diag('Test died: ' || errmsg);
                errmsg := NULL;
            END IF;
       END;
                EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb + 1;
        PERFORM _set('curr_test', tnumb);
        PERFORM _set('failed', tfaild);
                RETURN NEXT ok(tok, tests[i]);
        IF NOT tok THEN tfaild := tfaild + 1;
 END IF;
 END IF;
    END LOOP;
        FOR tap IN SELECT * FROM _runem(shutdown, false) LOOP RETURN NEXT tap;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM _finish( COALESCE(_get('curr_test'), 0), 0, tfaild ) LOOP        RETURN NEXT tap;
    END LOOP;
        PERFORM _cleanup();
    RETURN;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT, TEXT, BOOLEAN )RETURNS SETOF TEXT AS $$DECLARE    tnumb   INTEGER;
    aok     BOOLEAN;
    adescr  TEXT;
    res     BOOLEAN;
    descr   TEXT;
    adiag   TEXT;
    have    ALIAS FOR $1;
    eok     ALIAS FOR $2;
    name    ALIAS FOR $3;
    edescr  ALIAS FOR $4;
    ediag   ALIAS FOR $5;
    matchit ALIAS FOR $6;
BEGIN        tnumb := currval('__tresults___numb_seq');
        aok    := substring(have, 1, 2) = 'ok';
    adescr := COALESCE(substring(have FROM  E'(?:not )?ok [[:digit:]]+ - ([^\n]+)'), '');
        EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb;
    IF NOT aok THEN PERFORM _set('failed', _get('failed') - 1);
 END IF;
 END IF;
        descr := coalesce( name || ' ', 'Test ' ) || 'should ';
        RETURN NEXT is(        aok,        eok,        descr || CASE eok WHEN true then 'pass' ELSE 'fail' END    );
        IF edescr IS NOT NULL THEN        RETURN NEXT is(            adescr,            edescr,            descr || 'have the proper description'        );
    END IF;
        IF ediag IS NOT NULL THEN                adiag := substring(            have            FROM CASE WHEN aok THEN 4 ELSE 9 END + char_length(tnumb::text)        );
                IF adescr <> '' THEN            adiag := substring(                adiag FROM 1 + char_length( ' - ' || substr(diag( adescr ), 3) )            );
        END IF;
        IF NOT aok THEN                        adiag := substring(adiag FROM 1 + char_length(diag(                'Failed test ' || tnumb ||                CASE adescr WHEN '' THEN '' ELSE COALESCE(': "' || adescr || '"', '') END            )));
        END IF;
        IF ediag <> '' THEN                      adiag := substring(adiag FROM 2);
        END IF;
                adiag := replace( substring(adiag from 3), E'\n# ', E'\n' );
                IF matchit THEN            RETURN NEXT matches(                adiag,                ediag,                descr || 'have the proper diagnostics'            );
        ELSE            RETURN NEXT is(                adiag,                ediag,                descr || 'have the proper diagnostics'            );
        END IF;
    END IF;
        RETURN;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION _cleanup()RETURNS boolean AS $$    DROP SEQUENCE __tresults___numb_seq;
    DROP TABLE __tcache__;
    DROP SEQUENCE __tcache___id_seq;
    SELECT TRUE;
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION has_sequence ( NAME, NAME )RETURNS TEXT AS $$    SELECT ok(        _rexists( 'S', $1, $2 ),        'Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist'    );
$$ LANGUAGE SQL;
GRANT SELECT ON tap_funky           TO PUBLIC;
GRANT SELECT ON pg_all_foreign_keys TO PUBLIC;
